import goodStorage from 'good-storage'

// 获取数组元素的类型
type EleOfArr<T> = T extends Array<infer E> ? E : never

// 从数组的每个元素中挑选出指定字段的值
function getValArrOfObj<T extends any[], K extends keyof EleOfArr<T>, E = EleOfArr<T>>(t: T, k: K) {
  // 动态解构赋值
  return t.map(({ [k]: v }: E) => v)
}

// 判断val是不是一个普通对象
export const isPlainObject = (val: unknown): val is object => Object.prototype.toString.call(val) === '[object Object]'

export const enum OPTION {
  ACCUMU = 0, // 数组(元素)累加
  ADDORAPPENDOBJTOARR = 2, // 把对象添加或追加到数组中
  NONE = -1 // 什么都不做
}

// 缓存工具类
class Storage {
  static storage = new Storage()

  remove(key: string): any
  remove(key: string, option: OPTION, propkey: string, propvalue: any): any
  remove(key: string, option: OPTION = OPTION.NONE, propKey: string = '', propvalue?: any) {
    if (option === OPTION.ADDORAPPENDOBJTOARR) {
      const arr: any[] = goodStorage.get(key, [])
      const keyValOfObj = getValArrOfObj(arr, propKey)
      const eleIndex = keyValOfObj.indexOf(propvalue) // 获取传递的propKey值是propvalue在数组的哪个(元素)对象中
      if (eleIndex !== -1) {
        arr.splice(eleIndex, 1)
        goodStorage.set(key, arr) // 覆盖Local Storage 中的数组
      }
    } else {
      goodStorage.remove(key) // 根据指定的key移除对应 Local Storage 中对应的缓存
    }
  }

  /**
   * 
   * @param key 缓存的对象名
   * @param value 新增或累加的对象
   * @param propKey 新增对象的唯一标识key
   * @param propvalue 新增对象的唯一标识value
   * @returns 返回一个新对象，并缓存过起来
   */
  set(key: string, value: string): any // 根据指定的key缓存一个对应字符串值
  set(key: string, value: object): any // 根据指定的key缓存一个对应的对象
  set(key: string, value: any[]): any // 根据指定的key缓存一个对应的数组
  set(key: string, value: any[], option: OPTION): any // 根据指定的key将数组累加到缓存对象中
  set(key: string, value: object, option: OPTION, propKey: string, propvalue: any): any
  set(key: string, value: object | string, option: OPTION = OPTION.NONE, propKey: string = '', propvalue?: any) {
    if (isPlainObject(value) && option === OPTION.ADDORAPPENDOBJTOARR) {
      const arr: any[] = goodStorage.get(key, []) // 如果缓存中没有获取指定key的值，则默认值为[]空数组
      const keyValsOfObj = getValArrOfObj(arr, propKey) // 从缓存数组中获取每个元素指定的属性对应的值组件的新数组
      if (propKey.length > 0 && propvalue) {
        if (!keyValsOfObj.includes(propvalue)) { // 判断缓存数组中指定字段的值中是否包含 propvalue (新增)
          arr.push(value) // 将对象添加到缓存数组中
        } else {
          const index = keyValsOfObj.indexOf(propvalue)
          if (index !== -1) arr[index] = value // 覆盖旧的，实现累加
        }
        goodStorage.set(key, arr)
        return arr
      }
    } else if (Array.isArray(value) && option === OPTION.ACCUMU) {
      const arr: any[] = goodStorage.get(key, [])
      arr.push(...value)
      goodStorage.set(key, arr)
      return arr
    }
    // 其他情况直接覆盖
    goodStorage.set(key, value)
    return value
  }

  get(key: string): any
  get(key: string, option: OPTION): any
  get(key: string, option: OPTION = OPTION.NONE) {
    if (option === OPTION.ACCUMU || option === OPTION.ADDORAPPENDOBJTOARR) {
      return goodStorage.get(key, []) // 如果缓存中没有保存则返回一个空数组当作默认值
    }
    return goodStorage.get(key)
  }
}

export default Storage.storage
